﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GFluentCode.Tools
{
    /// <summary>
	/// 日期时间对儿(日期时间范围)。
	/// </summary>	
    [Serializable]
    public sealed class GDatePair
    {
        /// <summary>
        /// 开始时间(最小时间)
        /// </summary>
        public DateTime? Begin
        {
            get;
            set;
        }

        /// <summary>
        /// 结束时间(最大时间)
        /// </summary>
        public DateTime? Final
        {
            get;
            set;
        }

        /// <summary>
        /// 结束时间与开始时间的时间间隔
        /// </summary>        
        public TimeSpan TimeSpan
        {
            get
            {
                if (this.Final == null || this.Begin == null) return new TimeSpan(0);

                if (!(this.Final > this.Begin))
                {
                    return (DateTime)this.Begin - (DateTime)this.Final;
                }
                return (DateTime)this.Final - (DateTime)this.Begin;
            }
        }

        /// <summary>
        /// 日期时间对儿是否为空。
        /// </summary>        
        public bool IsEmpty
        {
            get
            {
                return this.Begin == null && this.Final == null;
            }
        }

        /// <summary>
        /// 获取空日期时间对儿。
        /// </summary>
        public static GDatePair Empty
        {
            get
            {
                return new GDatePair();
            }
        }

        /// <summary>
        /// 初始化日期时间对儿。
        /// </summary>
        public GDatePair() : this(null, null)
        {
        }

        /// <summary>
        /// 初始化日期时间对儿。
        /// </summary>
        /// <param name="begin">开始时间(最小时间)</param>
        /// <param name="final">结束时间(最大时间)</param>
        public GDatePair(DateTime? begin, DateTime? final)
        {
            this.Begin = begin;
            this.Final = final;
        }

        /// <summary>
        /// 初始化日期时间对儿。
        /// </summary>
        /// <param name="begin">开始时间(最小时间)的计时周期数(以 100 纳秒为单位表示的日期和时间)。</param>
        /// <param name="final">结束时间(最大时间)的计时周期数(以 100 纳秒为单位表示的日期和时间)。</param>
        public GDatePair(long begin, long final) : this(new DateTime(begin), new DateTime(final))
        {
        }

        /// <summary>
        /// 判断日期是否包含在日期时间对儿表示的时间范围内。
        /// </summary>
        public bool Contains(DateTime date)
        {
            return date >= this.Begin && date <= this.Final;
        }

        /// <summary>
        /// 判断是否包含目标日期时间对儿(相同的对儿视为包含，特例:空对儿包括空对儿)。
        /// </summary>
        public bool Contains(GDatePair pair)
        {
            return this == pair || (pair != null && pair.Begin >= this.Begin && pair.Final <= this.Final);
        }

        /// <summary>
        /// 判断是否包含目标日期时间对儿(相同的对儿视为包含，特例:空对儿包括空对儿)。
        /// </summary>
        public bool Contains(DateTime begin, DateTime final)
        {
            return this.Contains(new GDatePair(begin, final));
        }

        /// <summary>
        /// 获取与目标日期时间对儿产生的日期时间对儿交集(空对儿表示无交集)。
        /// </summary>
        public GDatePair Intersect(GDatePair pair)
        {
            if (this.IsEmpty || pair == null)
            {
                return GDatePair.Empty;
            }
            if (this.Begin > pair.Final || this.Final < pair.Begin)
            {
                return GDatePair.Empty;
            }
            return new GDatePair(
                Math.Max(((DateTime)this.Begin).Ticks,
                ((DateTime)pair.Begin).Ticks),
                Math.Min(((DateTime)this.Final).Ticks,
                ((DateTime)pair.Final).Ticks));
        }

        /// <summary>
        /// 获取与目标日期时间对儿产生的日期时间对儿交集(空对儿表示无交集)。
        /// </summary>
        public GDatePair Intersect(DateTime begin, DateTime final)
        {
            return this.Intersect(new GDatePair(begin, final));
        }

        /// <summary>
        /// 日期时间对儿的字符串表达式
        /// </summary>
        public override string ToString()
        {
            if (this.IsEmpty)
            {
                return "";
            }
            return this.ToString("yyyy-MM-dd HH:mm:ss.fff", " - ");
        }

        /// <summary>
        /// 日期时间对儿的字符串表达式
        /// </summary>
        /// <param name="format">日期格式化字符串</param>
        /// <param name="delimiter">时间对儿分隔符</param>
        public string ToString(string format, string delimiter)
        {
            if (this.IsEmpty)
            {
                return "";
            }
            DateTime dateTime = (this.Final == null) ? new DateTime(9999, 12, 31, 23, 59, 59) : (DateTime)this.Final;
            return ((DateTime)this.Begin).ToString(format) + delimiter + dateTime.ToString(format);
        }

        /// <summary>
        /// 确定指定的对象实例是否等于当前日期时间对儿。
        /// </summary>
        public override bool Equals(object obj)
        {
            return this == obj as GDatePair;
        }

        /// <summary>
        /// 获取日期时间对儿的哈希值。
        /// </summary>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// 判断日期时间对儿是否相同(null 和 IsEmpty 都视为空)。
        /// </summary>
        public static bool operator ==(GDatePair left, GDatePair right)
        {
            if (left.GIsEmpty(true) && right.GIsEmpty(true)) return true;

            if (left == null || left.IsEmpty)
            {
                return right == null || right.IsEmpty;
            }
            return right != null && !right.IsEmpty && left.Begin == right.Begin && left.Final == right.Final;
        }

        /// <summary>
        /// 判断日期时间对儿是否不同(null 和 IsEmpty 都视为空)。
        /// </summary>
        public static bool operator !=(GDatePair left, GDatePair right)
        {
            return !(left == right);
        }

        /// <summary>
        /// 隐形转换
        /// </summary>
        public static implicit operator string(GDatePair value)
        {
            if (value == null)
            {
                return GDatePair.Empty.ToString();
            }
            return value.ToString();
        }

        /// <summary>
        /// 隐形转换
        /// </summary>
        public static implicit operator GDatePair(string value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                return GDatePair.Empty;
            }
            string[] array = value.Split(new string[]
            {
                " - "
            }, StringSplitOptions.None);
            return new GDatePair(array[0].GToDateTime(), array[1].GToDateTime());
        }
    }
}
